"""
安全相关工具函数
"""

from datetime import datetime, timedelta
from typing import Optional, Dict, Any
import secrets
import hashlib
from passlib.context import CryptContext
from jose import JWTError, jwt

from app.config import settings

# 密码加密上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def get_password_hash(password: str) -> str:
    """生成密码哈希"""
    return pwd_context.hash(password)


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """验证密码"""
    return pwd_context.verify(plain_password, hashed_password)


def create_access_token(data: Dict[str, Any], expires_delta: Optional[timedelta] = None) -> str:
    """创建JWT访问令牌"""
    to_encode = data.copy()
    
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
    return encoded_jwt


def decode_access_token(token: str) -> Optional[Dict[str, Any]]:
    """解码JWT访问令牌"""
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
        return payload
    except JWTError:
        return None


def generate_verification_token() -> str:
    """生成验证令牌"""
    return secrets.token_urlsafe(32)


def generate_verification_code() -> str:
    """生成6位数字验证码"""
    return f"{secrets.randbelow(1000000):06d}"


def verify_verification_token(token: str, stored_token: str, expires_at: datetime) -> bool:
    """验证验证令牌"""
    if not token or not stored_token:
        return False
    
    # 检查是否过期
    if datetime.utcnow() > expires_at:
        return False
    
    # 使用安全的字符串比较
    return secrets.compare_digest(token, stored_token)


def generate_api_key() -> str:
    """生成API密钥"""
    return f"coal_stove_{secrets.token_urlsafe(32)}"


def hash_api_key(api_key: str) -> str:
    """哈希API密钥"""
    return hashlib.sha256(api_key.encode()).hexdigest()


def generate_session_id() -> str:
    """生成会话ID"""
    return secrets.token_urlsafe(24)


def create_password_reset_token(user_id: int) -> str:
    """创建密码重置令牌"""
    data = {
        "user_id": user_id,
        "type": "password_reset",
        "timestamp": datetime.utcnow().isoformat()
    }
    
    # 密码重置令牌有效期为1小时
    expires_delta = timedelta(hours=1)
    return create_access_token(data, expires_delta)


def verify_password_reset_token(token: str) -> Optional[int]:
    """验证密码重置令牌"""
    payload = decode_access_token(token)
    if not payload:
        return None
    
    if payload.get("type") != "password_reset":
        return None
    
    return payload.get("user_id")


def create_email_verification_token(user_id: int, email: str) -> str:
    """创建邮箱验证令牌"""
    data = {
        "user_id": user_id,
        "email": email,
        "type": "email_verification",
        "timestamp": datetime.utcnow().isoformat()
    }
    
    # 邮箱验证令牌有效期为24小时
    expires_delta = timedelta(hours=24)
    return create_access_token(data, expires_delta)


def verify_email_verification_token(token: str) -> Optional[Dict[str, Any]]:
    """验证邮箱验证令牌"""
    payload = decode_access_token(token)
    if not payload:
        return None
    
    if payload.get("type") != "email_verification":
        return None
    
    return {
        "user_id": payload.get("user_id"),
        "email": payload.get("email")
    }


def mask_email(email: str) -> str:
    """邮箱脱敏"""
    if "@" not in email:
        return email
    
    local, domain = email.split("@", 1)
    
    if len(local) <= 2:
        masked_local = "*" * len(local)
    else:
        masked_local = local[0] + "*" * (len(local) - 2) + local[-1]
    
    return f"{masked_local}@{domain}"


def mask_phone(phone: str) -> str:
    """手机号脱敏"""
    if len(phone) < 7:
        return phone
    
    return phone[:3] + "*" * (len(phone) - 6) + phone[-3:]


def generate_csrf_token() -> str:
    """生成CSRF令牌"""
    return secrets.token_urlsafe(32)


def validate_password_strength(password: str) -> Dict[str, Any]:
    """验证密码强度"""
    result = {
        "is_valid": True,
        "score": 0,
        "issues": []
    }
    
    # 长度检查
    if len(password) < 8:
        result["issues"].append("密码长度不能少于8位")
        result["is_valid"] = False
    else:
        result["score"] += 1
    
    # 包含字母
    if not any(c.isalpha() for c in password):
        result["issues"].append("密码必须包含字母")
        result["is_valid"] = False
    else:
        result["score"] += 1
    
    # 包含数字
    if not any(c.isdigit() for c in password):
        result["issues"].append("密码必须包含数字")
        result["is_valid"] = False
    else:
        result["score"] += 1
    
    # 包含大写字母
    if any(c.isupper() for c in password):
        result["score"] += 1
    
    # 包含小写字母
    if any(c.islower() for c in password):
        result["score"] += 1
    
    # 包含特殊字符
    special_chars = "!@#$%^&*()_+-=[]{}|;:,.<>?"
    if any(c in special_chars for c in password):
        result["score"] += 1
    
    # 评估强度
    if result["score"] >= 5:
        result["strength"] = "strong"
    elif result["score"] >= 3:
        result["strength"] = "medium"
    else:
        result["strength"] = "weak"
    
    return result
